
ifndef FISHNET_BUILD_ENVIRONMENT

debug:  export FISHNET_BUILD_ENVIRONMENT := debug
prod:   export FISHNET_BUILD_ENVIRONMENT := prod
clean:  export FISHNET_BUILD_ENVIRONMENT := debug

FISHNET_PREVIOUS_BUILD_ENV=`cat .fishnet_last_build_env 2>/dev/null`

debug prod:
	@touch .fishnet_last_build_env
	@if test "$(FISHNET_PREVIOUS_BUILD_ENV)" = "$(FISHNET_BUILD_ENVIRONMENT)"; then \
    make all; \
	else \
	  echo $(FISHNET_BUILD_ENVIRONMENT) > .fishnet_last_build_env; \
	  make clean; \
	  make all $(MAKEFLAGS); \
	fi

clean:
	@make clean

.PHONY: debug prod clean

else

# Environment
CXX        := `which g++`
EXEC_DIR   := bin
OBJECT_DIR := build

# Compilation Flags
COMMON_COMPILE_FLAGS := -ggdb3 -pipe -pthread -Wall -Wextra -Werror \
                        -I$(BOOST_HOME)/include
DEV_COMPILE_FLAGS    := $(COMMON_COMPILE_FLAGS)
PROD_COMPILE_FLAGS   := $(COMMON_COMPILE_FLAGS) -O3 -fno-strict-aliasing

# Callable variables (i.e. functions)
find_in_dir_with_suffix = $(foreach dir,$(1),$(shell find $(dir) -name "*.$(2)"))
dependencies = -MMD -MF $(1:.o=.d) -MT $(1)
dev_compile  = $(CXX) $(DEV_COMPILE_FLAGS) $(call dependencies,$(OBJECT_DIR)/$(2)) \
               -c $(1) -o $(OBJECT_DIR)/$(2)
prod_compile = $(CXX) $(PROD_COMPILE_FLAGS) $(call dependencies,$(OBJECT_DIR)/$(2)) \
               -c $(1) -o $(OBJECT_DIR)/$(2)
echo_and_execute = echo $(1); $(1)

# Main Source Files
MAIN_CXX_SOURCE_ROOT_DIR := src/main
MAIN_CXX_HEADER_FILES := $(call find_in_dir_with_suffix,$(MAIN_CXX_SOURCE_ROOT_DIR),hpp)
MAIN_CXX_HEADER_FILES := $(call find_in_dir_with_suffix,$(MAIN_CXX_SOURCE_ROOT_DIR),inl)
MAIN_CXX_IMPL_FILES   := $(call find_in_dir_with_suffix,$(MAIN_CXX_SOURCE_ROOT_DIR),cpp)

# Main Build Targets
MAIN_OBJECTS := $(addprefix $(OBJECT_DIR)/,$(subst src/,,$(MAIN_CXX_IMPL_FILES:.cpp=.o)))
MAIN_OBJECT_DIRS := $(sort $(dir ($MAIN_OBJECTS)))
MAIN_TARGET_LIBRARY := $(EXEC_DIR)/libfishnet.a

all: $(MAIN_TARGET_LIBRARY) main_init 

clean:
	rm -rf $(EXEC_DIR)/* $(OBJECT_DIR)/*

main_init:
	@mkdir -p $(sort $(dir $(MAIN_OBJECTS)))

$(MAIN_TARGET_LIBRARY): $(MAIN_OBJECTS)
	@mkdir -p $(dir $(MAIN_TARGET_LIBRARY))
	ar rcs $(MAIN_TARGET_LIBRARY) $(MAIN_OBJECTS)

$(OBJECT_DIR)/main/%.o: | main_init
	@if test "$(FISHNET_BUILD_ENVIRONMENT)" = "debug"; then \
    $(call echo_and_execute,$(call dev_compile,src/main/$*.cpp,main/$*.o)); \
	else \
    $(call echo_and_execute,$(call prod_compile,src/main/$*.cpp,main/$*.o)); \
  fi

%.d:

.PHONY: all clean main_init

define depends_include_template
-include $(1)

endef

$(eval $(foreach dep,$(wildcard $(MAIN_OBJECTS:.o=.d)),$(call depends_include_template,$(dep))))

endif

